/**
 * 订阅消息管理工具类
 * 用于统一管理各类订阅消息的状态和操作
 */
import API from '@/api/index.js';
import { TEMPLATE_TYPES, TEMPLATE_GROUPS } from '@/utils/constants/subscribe.js';
import {
  SUBSCRIBE_PROMPT_INTERVAL,
  DEFAULT_PROMPT_INTERVAL
} from '@/utils/constants/subscribe-config.js';

// 存储键名常量
export const STORAGE_KEYS = {
  // 漂流瓶相关
  BOTTLE: {
    SUBSCRIBED: 'bottle_subscribed',          // 是否已订阅
    SUBSCRIBE_TIME: 'bottle_subscribe_time',  // 订阅时间
    LAST_PROMPT: 'bottle_subscribe_last_prompt', // 上次提示时间
  },
  // 聊天相关
  CHAT: {
    SUBSCRIBED: 'chat_subscribed',            // 是否已订阅
    SUBSCRIBE_TIME: 'chat_subscribe_time',    // 订阅时间
    LAST_PROMPT: 'chat_subscribe_last_prompt', // 上次提示时间
  },
  // 资料相关
  PROFILE: {
    SUBSCRIBED: 'profile_subscribed',         // 是否已订阅
    SUBSCRIBE_TIME: 'profile_subscribe_time', // 订阅时间
    LAST_PROMPT: 'profile_subscribe_last_prompt', // 上次提示时间
  },
  // 动态相关
  POST: {
    SUBSCRIBED: 'post_subscribed',            // 是否已订阅
    SUBSCRIBE_TIME: 'post_subscribe_time',    // 订阅时间
    LAST_PROMPT: 'post_subscribe_last_prompt', // 上次提示时间
  }
  // 可以添加其他类型
};

/**
 * 创建订阅消息键名
 * @param {String} prefix 前缀
 * @returns {Object} 订阅消息键名集合
 */
export function createSubscribeKeys(prefix) {
  return {
    SUBSCRIBED: `${prefix}_subscribed`,
    SUBSCRIBE_TIME: `${prefix}_subscribe_time`,
    LAST_PROMPT: `${prefix}_subscribe_last_prompt`
  };
}

/**
 * 订阅消息管理类
 */
class SubscribeManager {
  /**
   * 获取指定类型的订阅模板ID列表
   * @param {String} type 模板类型，例如"BOTTLE_ALL"
   * @returns {Promise<Array>} 模板ID列表
   */
  async getTemplateIds(type) {
    // #ifdef MP-WEIXIN
    try {
      const res = await API.subscribe.getTemplateList();
      if (!res) return [];

      // 使用指定的类型过滤模板
      const targetTemplates = TEMPLATE_GROUPS[type] || [];
      const filteredTemplates = res.filter(item =>
        targetTemplates.includes(item.title)
      );

      // 返回模板ID数组
      return filteredTemplates.map(item => item.id);
    } catch (error) {
      console.error(`获取${type}订阅模板失败:`, error);
      return [];
    }
    // #endif

    // 非微信环境返回空数组
    // #ifndef MP-WEIXIN
    return [];
    // #endif
  }

  /**
   * 检查是否需要显示订阅提示
   * @param {String} storageKey 订阅状态存储键名
   * @param {String} promptKey 提示时间存储键名
   * @param {String} subscribeType 订阅类型，用于获取对应的时间间隔配置，如"CHAT"、"BOTTLE"
   * @returns {Boolean} 是否需要显示
   */
  shouldShowPrompt(storageKey, promptKey, subscribeType = '') {
    // #ifdef MP-WEIXIN
    // 检查是否已订阅
    const subscribed = uni.getStorageSync(storageKey);
    if (subscribed) return false;

    // 检查是否在配置的时间间隔内提示过
    const lastPromptTime = uni.getStorageSync(promptKey);
    if (lastPromptTime) {
      const now = Date.now(); // 当前时间戳
      const interval = this.getPromptInterval(subscribeType); // 获取配置的时间间隔

      // 如果上次提示时间 + 间隔时间 > 当前时间，说明还在间隔期内
      if (parseInt(lastPromptTime) + interval > now) {
        return false;
      }
    }

    // 未订阅且不在时间间隔内，应该显示提示
    return true;
    // #endif

    // 非微信环境不需要显示
    // #ifndef MP-WEIXIN
    return false;
    // #endif
  }

  /**
   * 获取订阅提示的时间间隔（毫秒）
   * @param {String} subscribeType 订阅类型
   * @returns {Number} 时间间隔（毫秒）
   */
  getPromptInterval(subscribeType) {
    if (!subscribeType) return DEFAULT_PROMPT_INTERVAL;

    // 从配置中获取指定类型的间隔
    return SUBSCRIBE_PROMPT_INTERVAL[subscribeType] || DEFAULT_PROMPT_INTERVAL;
  }

  /**
   * 记录订阅提示时间
   * @param {String} promptKey 提示时间存储键名
   */
  recordPromptTime(promptKey) {
    uni.setStorageSync(promptKey, Date.now().toString());
  }

  /**
   * 请求订阅消息授权
   * @param {Array} templateIds 模板ID列表
   * @returns {Promise<Object>} 订阅结果
   */
  requestSubscribe(templateIds) {
    return new Promise((resolve, reject) => {
      // #ifdef MP-WEIXIN
      // 无可用模板
      if (!templateIds || templateIds.length === 0) {
        reject(new Error('无可用订阅模板'));
        return;
      }

      wx.requestSubscribeMessage({
        tmplIds: templateIds,
        success: (res) => {
          // 检查是否至少有一个模板被接受
          const acceptedTemplates = templateIds.filter(id => res[id] === 'accept');
          const rejectedTemplates = templateIds.filter(id => res[id] === 'reject');
          const hasAccepted = acceptedTemplates.length > 0;
          const allRejected = rejectedTemplates.length === templateIds.length;

          // 更新订阅状态
          if (hasAccepted) {
            this.setSubscribeStatus(true, STORAGE_KEYS.BOTTLE.SUBSCRIBED, STORAGE_KEYS.BOTTLE.SUBSCRIBE_TIME);
          } else if (allRejected) {
            // 所有模板都被拒绝，提示用户如何重新开启
            this.showSubscribeGuide();
          }

          resolve({
            accepted: hasAccepted,
            rejected: rejectedTemplates.length > 0,
            templates: acceptedTemplates,
            result: res
          });
        },
        fail: (error) => {
          console.error('订阅请求失败:', error);

          // 引导用户去设置页面开启
          if (error && (error.errCode === 20004 || error.errCode === 10004)) {
            this.showSubscribeGuide();
          }

          reject(error);
        }
      });
      // #endif

      // 非微信环境
      // #ifndef MP-WEIXIN
      reject(new Error('当前环境不支持订阅消息'));
      // #endif
    });
  }

  /**
   * 静默订阅 - 用于已订阅用户的自动续期
   * @param {String} type 模板类型
   * @param {String} subscribeKey 订阅状态键名
   * @param {String} timeKey 订阅时间键名
   * @param {String} promptKey 提示时间键名
   * @param {Function} callback 回调函数，返回{accepted: Boolean, rejected: Boolean}
   * @returns {Promise<Object>} 订阅结果
   */
  async silentSubscribe(type, subscribeKey, timeKey, promptKey, callback) {
    // #ifdef MP-WEIXIN
    try {
      // 获取模板ID
      const templateIds = await this.getTemplateIds(type);
      if (templateIds.length === 0) {
        console.log('没有可用的订阅模板，跳过订阅过程');
        if (callback) callback({ accepted: false, rejected: false, reason: 'no_templates' });
        return { success: false, reason: 'no_templates' };
      }

      // 先检查订阅消息总开关状态
      return new Promise((resolve) => {
        wx.getSetting({
          withSubscriptions: true,
          success: (settingRes) => {
            // 检查总开关是否打开
            const mainSwitchOn = settingRes.subscriptionsSetting &&
                               settingRes.subscriptionsSetting.mainSwitch;

            if (!mainSwitchOn) {
              // 总开关未开启，引导用户去设置页面
              console.log('订阅消息总开关未开启');
              this.setSubscribeStatus(false, subscribeKey, timeKey);

              // 清除上次提示记录以便日后再次提示
              uni.removeStorageSync(promptKey);

              // 引导用户打开设置页面开启总开关
              this.showSubscribeGuide();

              if (callback) callback({ accepted: false, rejected: true, reason: 'main_switch_off' });

              resolve({
                success: false,
                reason: 'main_switch_off'
              });
              return;
            }

            // 总开关已开启，继续请求订阅消息
            wx.requestSubscribeMessage({
              tmplIds: templateIds,
              success: (res) => {
                // 检查是否有模板被接受
                const acceptedTemplates = templateIds.filter(id => res[id] === 'accept');
                const rejectedTemplates = templateIds.filter(id => res[id] === 'reject');
                const hasAccepted = acceptedTemplates.length > 0;
                const allRejected = rejectedTemplates.length === templateIds.length;

                if(hasAccepted){
                  // 显示订阅成功提示
                  this.setSubscribeStatus(true, subscribeKey, timeKey);
                } else if(allRejected) {
                  // 所有模板都被拒绝，提示用户如何重新开启
                  this.showSubscribeGuide();

                  // 如果用户取消了授权，清除上次提示记录以便日后再次提示
                  uni.removeStorageSync(promptKey);
                }

                // 调用回调函数，通知调用者用户的选择
                if (callback) callback({ accepted: hasAccepted, rejected: allRejected });

                resolve({
                  success: true,
                  accepted: hasAccepted,
                  rejected: rejectedTemplates.length > 0,
                  templates: acceptedTemplates
                });
              },
              fail: (error) => {
                console.error('静默订阅失败:', error);

                // 特定错误码处理 (用户拒绝或未授权)
                if (error && (error.errCode === 20004 || error.errCode === 10004)) {
                  this.setSubscribeStatus(false, subscribeKey, timeKey);
                  uni.removeStorageSync(promptKey);

                  // 引导用户打开设置
                  this.showSubscribeGuide();
                }

                if (callback) callback({ accepted: false, rejected: true, error });

                resolve({
                  success: false,
                  reason: 'request_failed',
                  error
                });
              }
            });
          },
          fail: (error) => {
            console.error('获取订阅设置失败:', error);
            if (callback) callback({ accepted: false, rejected: true, error });

            resolve({
              success: false,
              reason: 'get_setting_failed',
              error
            });
          }
        });
      });
    } catch (error) {
      console.error('静默订阅异常:', error);
      if (callback) callback({ accepted: false, rejected: true, error });
      return { success: false, reason: 'exception', error };
    }
    // #endif

    // 非微信环境
    // #ifndef MP-WEIXIN
    if (callback) callback({ accepted: false, rejected: false, reason: 'not_supported' });
    return { success: false, reason: 'not_supported' };
    // #endif
  }

  /**
   * 设置订阅状态
   * @param {Boolean} subscribed 是否已订阅
   * @param {String} subscribeKey 订阅状态键名
   * @param {String} timeKey 订阅时间键名
   */
  setSubscribeStatus(subscribed, subscribeKey, timeKey) {
    // 设置订阅状态
    uni.setStorageSync(subscribeKey, subscribed ? 1 : 0);

    // 记录订阅时间
    if (subscribed) {
      uni.setStorageSync(timeKey, Date.now());
    }
  }

  /**
   * 检查是否已订阅
   * @param {String} subscribeKey 存储键名
   * @returns {Boolean} 是否已订阅
   */
  isSubscribed(subscribeKey) {
    return !!uni.getStorageSync(subscribeKey);
  }

  /**
   * 清除订阅状态
   * @param {Object} keys 要清除的键集合，默认为漂流瓶相关的所有键
   */
  clearSubscribeStatus(keys) {
    const targetKeys = keys || {
      subscribed: STORAGE_KEYS.BOTTLE.SUBSCRIBED,
      time: STORAGE_KEYS.BOTTLE.SUBSCRIBE_TIME,
      prompt: STORAGE_KEYS.BOTTLE.LAST_PROMPT
    };

    if (targetKeys.subscribed) {
      uni.removeStorageSync(targetKeys.subscribed);
    }

    if (targetKeys.time) {
      uni.removeStorageSync(targetKeys.time);
    }

    if (targetKeys.prompt) {
      uni.removeStorageSync(targetKeys.prompt);
    }
  }

  /**
   * 显示订阅引导，帮助用户在设置中重新开启订阅权限
   * @param {Function} callback 设置页面关闭后的回调函数
   */
  showSubscribeGuide(callback) {
    // #ifdef MP-WEIXIN
    uni.showModal({
      title: '开启订阅消息',
      content: '您之前选择了不接收订阅消息，如需重新开启，请前往设置页面-【通知管理】授权',
      confirmText: '去开启',
      showCancel: false,
      success: (res) => {
        if (res.confirm) {
          // 打开设置页面前记录当前时间戳
          uni.setStorageSync('subscribe_guide_timestamp', Date.now());

          // 打开设置页面
          uni.openSetting({
            success: (settingRes) => {
              console.log('设置页面打开成功', settingRes);
            },
            fail: (err) => {
              console.error('打开设置页面失败', err);
              // 如果打开失败，直接调用回调
              if (callback) callback(false);
            }
          });

          // 保存回调函数到全局变量，供页面onShow时调用
          if (callback) {
            getApp().globalData = getApp().globalData || {};
            getApp().globalData.subscribeGuideCallback = callback;
          }
        } else {
          // 用户选择取消，调用回调并传递false
          if (callback) callback(false);
        }
      }
    });
    // #endif

    // #ifndef MP-WEIXIN
    if (callback) callback(false);
    // #endif
  }

  /**
   * 检查用户从设置页面返回后的订阅授权状态
   * @param {Function} successCallback 授权成功后的回调函数
   * @param {Function} failCallback 未授权时的回调函数
   * @param {String} type 模板类型，例如"POST_ALL"
   * @param {String} subscribeKey 订阅状态键名
   * @param {String} timeKey 订阅时间键名
   * @param {String} promptKey 提示时间键名
   * @returns {Boolean} 是否处理了返回事件
   */
  checkFromSettingReturn(successCallback, failCallback, type, subscribeKey, timeKey, promptKey) {
    // #ifdef MP-WEIXIN
    // 检查是否从设置页面返回
    const timestamp = uni.getStorageSync('subscribe_guide_timestamp');
    if (timestamp) {
      // 如果时间戳存在且距离现在小于1分钟，认为是从设置页面返回的
      const now = Date.now();
      if (now - timestamp < 60000) { // 1分钟内
        // 清除时间戳
        uni.removeStorageSync('subscribe_guide_timestamp');

        // 从设置页面返回后，重新检查用户是否允许了订阅消息
        this.checkSubscriptionAuthorization((authorized) => {

          if (authorized) {

            uni.showModal({
              title: '温馨提示',
              content: '您已成功开启订阅消息',
              showCancel: false,
              success: (res) => {
                if (res.confirm) {

                  // 用户已授权，调用静默订阅方法执行实际的订阅操作
                  this.silentSubscribe(
                      type,
                      subscribeKey,
                      timeKey,
                      promptKey,
                      (result) => {
                        if (result && result.accepted) {
                          if (successCallback) successCallback(result);
                        }
                      }
                  );

                }
              }
            });

          } else {
            // 如果仍未订阅，调用失败回调
            if (failCallback) failCallback();
          }
        });
      }
    }
    return false;
    // #endif

    // #ifndef MP-WEIXIN
    return false;
    // #endif
  }

  /**
   * 检查订阅授权状态
   * @param {Function} callback 回调函数，接收一个布尔值参数表示是否授权
   */
  checkSubscriptionAuthorization(callback) {
    // #ifdef MP-WEIXIN
    // 使用getSetting获取用户授权设置
    wx.getSetting({
      withSubscriptions: true, // 获取用户订阅消息的订阅状态
      success: (res) => {
        // 检查是否有订阅消息授权相关信息
        if (res.subscriptionsSetting && res.subscriptionsSetting.mainSwitch) {
          // 检查总开关是否打开
          if (res.subscriptionsSetting.mainSwitch) {
            // 如果找到任何一个接受的模板，认为用户已授权
            const hasAuthorized = res.subscriptionsSetting.itemSettings &&
              Object.keys(res.subscriptionsSetting.itemSettings).some(key => {
                return res.subscriptionsSetting.itemSettings[key] === 'accept';
              });

            callback(hasAuthorized);
          } else {
            // 总开关未打开
            callback(false);
          }
        } else {
          // 没有订阅消息授权信息
          callback(false);
        }
      },
      fail: (err) => {
        console.error('获取授权设置失败', err);
        callback(false);
      }
    });
    // #endif

    // #ifndef MP-WEIXIN
    callback(false);
    // #endif
  }
}

// 导出单例
export default new SubscribeManager();
